package com.un.ebs.sys.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.un.ebs.core.enums.SexEnum;
import com.un.ebs.core.enums.UserTypeEnum;
import com.un.ebs.core.exception.BusinessEntityNotFoundException;
import com.un.ebs.core.exception.BusinessException;
import com.un.ebs.core.util.AESTool;
import com.un.ebs.core.util.SecurityUtils;
import com.un.ebs.core.util.StringUtils;
import com.un.ebs.customer.domain.Customer;
import com.un.ebs.customer.service.CustomerService;
import com.un.ebs.sys.domain.*;
import com.un.ebs.sys.dto.PersonnelAddDto;
import com.un.ebs.sys.dto.PersonnelRegisterDto;
import com.un.ebs.sys.dto.PersonnelUpdateDto;
import com.un.ebs.sys.mapper.*;
import com.un.ebs.sys.service.EntService;
import com.un.ebs.sys.service.PersonnelService;
import com.un.ebs.sys.service.UserService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author liubo
 * @since 2019-09-22
 */
@Service
public class PersonnelServiceImpl extends ServiceImpl<PersonnelMapper, Personnel> implements PersonnelService {

    @Resource
    private UserService userService;

    @Resource
    private EntService entService;

    @Resource
    private EntDeptMapper entDeptMapper;

    @Resource
    private AppTenantMapper appTenantMapper;

    @Resource
    private CustomerService customerService;

    @Resource
    private EntPersonnelMapper entPersonnelMapper;

    @Resource
    private PersonnelExtMapper personnelExtMapper;

    @Resource
    private AppUserRoleExtMapper appUserRoleExtMapper;

    @Resource
    private AppUserRoleMapper appUserRoleMapper;

    @Resource
    private UserWxMapper userWxMapper;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void add(PersonnelAddDto req) {

        User user = userService.queryByUserName(req.getUserName());
        if (user == null) {
            user = new User();
            user.setType(UserTypeEnum.USER);
            user.setUserName(req.getUserName());
            user.setPassword(AESTool.Encrypt(req.getPassword()));
            user.setIsDelete(false);
            user.setCurrentTenantId(SecurityUtils.getUserContent().getTenantId());
            user.insert();

            UserWx userWx = new UserWx();
            userWx.setUserId(user.getId());
            userWx.setTenantId(SecurityUtils.getTenantId());
            userWx.insert();
        } else {
            throw new BusinessException("用户名称不能重复。");
        }

        Personnel obj = queryByPhone(req.getTel());
        if (obj == null) {
            obj = new Personnel();
            obj.setUserId(user.getId());
            obj.setBirthDate(req.getBirthDate());
            obj.setEmail(req.getEmail());
            obj.setName(req.getName());
            obj.setSex(req.getSex());
            obj.setTel(req.getTel());
            obj.setIsDelete(false);
            obj.setSort(getBaseMapper().maxSort());
            obj.insert();

            EntPersonnel entPersonnel = new EntPersonnel();
            entPersonnel.setEntId(SecurityUtils.getUserContent().getEntId());
            entPersonnel.setDeptId(req.getDeptId());
            entPersonnel.setPersonnelId(obj.getId());
            entPersonnel.setSort(baseMapper.maxSort());
            entPersonnel.setIsDelete(false);
            entPersonnel.insert();
        } else {
            throw new BusinessException("手机号码不能重复。");
        }
    }

    @Transactional
    @Override
    public void addAdmin(String tenantId, String userName, String password, String personnelName, String phone) {

        AppTenant tenant = appTenantMapper.selectById(tenantId);
        if (tenant == null) {
            throw new BusinessEntityNotFoundException(tenantId, "租户");
        }

        User user = userService.queryByUserName(userName);
        if (user == null) {
            user = new User();
            user.setType(UserTypeEnum.TENANT_ADMIN);
            user.setUserName(userName);
            user.setPassword(AESTool.Encrypt(password));
            user.setIsDelete(false);
            user.setCurrentTenantId(tenantId);
            user.insert();

            UserWx userWx = new UserWx();
            userWx.setUserId(user.getId());
            userWx.setTenantId(tenantId);
            userWx.insert();
        } else {
            throw new BusinessException("用户名称不能重复。");
        }

        Personnel obj = queryByPhone(phone);
        if (obj == null) {
            obj = new Personnel();
            obj.setUserId(user.getId());
            obj.setName(personnelName);
            obj.setSex(SexEnum.Notdefine.getCode());
            obj.setTel(phone);
            obj.setIsDelete(false);
            obj.setSort(getBaseMapper().maxSort());
            obj.insert();

            EntPersonnel entPersonnel = new EntPersonnel();
            entPersonnel = new EntPersonnel();
            entPersonnel.setEntId(tenant.getEntId());
            entPersonnel.setPersonnelId(obj.getId());
            entPersonnel.setSort(baseMapper.maxSort());
            entPersonnel.setIsDelete(false);

            LambdaQueryWrapper<EntDept> lq = Wrappers.lambdaQuery();
            lq.eq(EntDept::getEntId, tenant.getEntId());
            lq.eq(EntDept::getName, "未指定名称");
            lq.eq(EntDept::getIsDelete, false);
            Optional<EntDept> dept = entDeptMapper.selectList(lq).stream().findFirst();
            if (dept.isPresent()) {
                entPersonnel.setDeptId(dept.get().getId());
            } else {
                EntDept entDept = new EntDept();
                entDept.setEntId(tenant.getEntId());
                entDept.setName("未指定名称");
                entDept.setSort(1);
                entDept.insert();
                entPersonnel.setDeptId(entDept.getId());
            }

            entPersonnel.insert();

            TenantAdmin admin = new TenantAdmin();
            admin.setTenantId(tenantId);
            admin.setUserId(user.getId());
            admin.insert();
        } else {
            throw new BusinessException("手机号码不能重复。");
        }
    }

    @Override
    public void moveToDept(String id, String deptId) {
        EntPersonnel entPersonnel = baseMapper.queryByEntAndPersonnel(SecurityUtils.getUserContent().getEntId(), id);
        if (entPersonnel == null) {
            //throw new BusinessException("当前企业下没有找到指定的人员。");
            entPersonnel = new EntPersonnel();
            entPersonnel.setEntId(SecurityUtils.getUserContent().getEntId());
            entPersonnel.setDeptId(deptId);
            entPersonnel.setPersonnelId(id);
            entPersonnel.setSort(baseMapper.maxSort());
            entPersonnel.setIsDelete(false);
        }

        entPersonnel.setDeptId(deptId);
        entPersonnel.insertOrUpdate();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void invite(String userName, String deptId) {
        User user = userService.queryByUserName(userName);
        if (user == null) {
            throw new BusinessEntityNotFoundException(userName, "用户");
        }
        if (user.getIsDelete()) {
            throw new BusinessException(user.getUserName() + " 用户已注销。");
        }

        Personnel personnel = queryByUserId(user.getId());
        if (personnel == null) {
            throw new BusinessException("指定的用户没有实名认证。");
        }
        if (personnel.getIsDelete()) {
            throw new BusinessException(personnel.getName() + " 人员已删除。");
        }

        if (StringUtils.isNullOrEmpty(deptId)) {
            throw new BusinessException("请指定部门。");
        }
        LambdaQueryWrapper<EntDept> queryDept = Wrappers.lambdaQuery();
        queryDept.eq(EntDept::getEntId, SecurityUtils.getUserContent().getEntId());
        queryDept.eq(EntDept::getId, deptId);
        EntDept dept = entDeptMapper.selectOne(queryDept);
        if (dept == null) {
            throw new BusinessException("指定的部门与当前不属于当前企业，操作无效。");
        }

        LambdaQueryWrapper<EntPersonnel> lq = Wrappers.lambdaQuery();
        lq.eq(EntPersonnel::getPersonnelId, personnel.getId());
        lq.eq(EntPersonnel::getEntId, SecurityUtils.getUserContent().getEntId());
        EntPersonnel obj = entPersonnelMapper.selectOne(lq);
        if (obj == null) {
            obj = new EntPersonnel();
            obj.setEntId(SecurityUtils.getUserContent().getEntId());
            obj.setPersonnelId(personnel.getId());
            obj.setDeptId(deptId);
            obj.setSort(entPersonnelMapper.maxSort(SecurityUtils.getUserContent().getEntId()));
            obj.insert();
        } else {
            EntDept entDept = entDeptMapper.selectById(obj.getDeptId());
            throw new BusinessException(String.format("用户 【%s】 已存在 【%s】 部门，不能重复添加。", personnel.getName(), entDept.getName()));
        }
    }

    @Transactional
    @Override
    public void register(PersonnelRegisterDto req) {
        if (!userService.checkRegisterCode(req.getPhone(), req.getSmsCode())) {
            throw new BusinessException("验证码不正确！");
        }
        User user = userService.queryByUserName(req.getPhone());
        if (user == null) {
            //throw new BusinessException("您已经是系统的用户，不能重复注册。");
            user = userService.getUserByOpenId(req.getOpenId());
            if (user == null) {
                //throw new BusinessException("您已经是系统的用户，不能重复注册。");
                user = new User();
                user.setType(UserTypeEnum.USER);
                user.setUserName(req.getPhone());
                user.setPassword(AESTool.Encrypt(UUID.randomUUID().toString()));
            }
        }
        user.setIsDelete(false);
        user.setCurrentTenantId(req.getTenantId());
        user.setOpenId(req.getOpenId());
        user.insertOrUpdate();

        UserWx userWx = userService.queryUserWx(req.getTenantId(), req.getOpenId());
        if (userWx == null) {
            userWx = new UserWx();
            userWx.setUserId(user.getId());
            userWx.setOpenId(req.getOpenId());
            userWx.setTenantId(req.getTenantId());
            userWx.insert();
        }

        Customer cust = customerService.queryCustByMobile(req.getPhone());
        if (cust == null) {
            cust = new Customer();
            cust.setName(req.getName());
            cust.setUserId(user.getId());
            cust.setPhone(req.getPhone());
            cust.setIsDelete(false);
            cust.setCreateAt(user.getId());
            cust.setCreateTime(new Date());
        }
        cust.setUserId(user.getId());
        cust.setTenantId(req.getTenantId());
        cust.insertOrUpdate();

        Personnel obj = queryByPhone(req.getPhone());
        if (obj == null) {
            obj = new Personnel();
            obj.setCreateAt(user.getId());
            obj.setCreateTime(new Date());
            obj.setSort(getBaseMapper().maxSort());
            obj.setIsRegisterAudit(false);
            obj.setTel(req.getPhone());
            if (req.getSex() != null) {
                obj.setSex(req.getSex().getValue());
            }
        }
        obj.setUserId(user.getId());
        obj.setName(req.getName());
        obj.setIsDelete(false);
        obj.setRegisterRemark(req.getRemark());
        obj.insertOrUpdate();

        Ent ent = entService.queryByTenantId(req.getTenantId());
        if (ent == null) {
            throw new BusinessException("指定的租户没有找到对应的企业信息。");
        }
        if (!entService.hasInTenant(req.getTenantId(), user.getId())) {
            EntPersonnel entPersonnel = new EntPersonnel();
            entPersonnel.setPersonnelId(obj.getId());
            entPersonnel.setEntId(ent.getId());
            entPersonnel.setDeptId(req.getDeptId());
            entPersonnel.setIsDelete(false);
            entPersonnel.setSort(entPersonnelMapper.maxSort(ent.getId()));
            entPersonnel.insert();
        } else {
            throw new BusinessException("你已经注册！");
        }

    }

    @Override
    public void registerAudit(String id) {
        LambdaQueryWrapper<EntPersonnel> lq = Wrappers.lambdaQuery();
        lq.eq(EntPersonnel::getEntId, SecurityUtils.getUserContent().getEntId());
        lq.eq(EntPersonnel::getPersonnelId, id);
        EntPersonnel entPersonnel = entPersonnelMapper.selectOne(lq);
        if (entPersonnel == null) {
            throw new BusinessException("你与指定的人员不在同一个企业中，不能进行此操作。");
        }

        Personnel obj = baseMapper.selectById(id);
        if (obj == null) {
            throw new BusinessEntityNotFoundException(id, "人员信息");
        }
        obj.setIsRegisterAudit(true);
        obj.updateById();
    }

    @Transactional
    @Override
    public void update(PersonnelUpdateDto req) {
        Personnel obj = queryEntPersonnel(req.getId());
        obj.setBirthDate(req.getBirthDate());
        obj.setEmail(req.getEmail());
        obj.setName(req.getName());
        obj.setSex(req.getSex());
        obj.setTel(req.getTel());
        obj.updateById();

        moveToDept(obj.getId(), req.getDeptId());
    }

    private Personnel queryEntPersonnel(String id) {
        EntPersonnel obj = entPersonnelMapper.selectById(id);
        if (obj != null) {
            return baseMapper.selectById(obj.getPersonnelId());
        }
        return null;
    }

    @Override
    public int delete(String id) {
        LambdaQueryWrapper<EntPersonnel> lq = Wrappers.lambdaQuery();
        lq.eq(EntPersonnel::getId, id);
        lq.eq(EntPersonnel::getEntId, SecurityUtils.getUserContent().getEntId());
        Optional<EntPersonnel> entPersonnel = entPersonnelMapper.selectList(lq).stream().findFirst();
        if (!entPersonnel.isPresent()) {
            return 0;
        }
        entPersonnel.get().deleteById();

        User user = userService.queryByPersonnelId(entPersonnel.get().getPersonnelId());
        if (user != null) {

            LambdaQueryWrapper<AppUserRole> lqUserRole = Wrappers.lambdaQuery();
            lqUserRole.eq(AppUserRole::getUserId, user.getId());
            lqUserRole.eq(AppUserRole::getTenantId, SecurityUtils.getTenantId());
            int cnt = appUserRoleMapper.delete(lqUserRole);

            LambdaQueryWrapper<UserWx> userWxQuery = Wrappers.lambdaQuery();
            userWxQuery.eq(UserWx::getUserId, user.getId());
            userWxQuery.eq(UserWx::getTenantId, SecurityUtils.getUserContent().getTenantId());
            cnt = userWxMapper.delete(userWxQuery);

            user.setOpenId(null);
            user.setCurrentTenantId(null);
            boolean updateStatus = user.updateById();
        }
        return 1;

    }

    @Override
    public int delete(String personnelId, String toPersonnelId) {
        LambdaQueryWrapper<EntPersonnel> lq = Wrappers.lambdaQuery();
        lq.eq(EntPersonnel::getPersonnelId, toPersonnelId);
        lq.eq(EntPersonnel::getEntId, SecurityUtils.getUserContent().getEntId());
        long cnt = entPersonnelMapper.selectCount(lq);
        if (cnt <= 0) {
            throw new BusinessException("指定的数据转移目标人员不存在。");
        }

        LambdaQueryWrapper<EntPersonnel> query = Wrappers.lambdaQuery();
        query.eq(EntPersonnel::getEntId, SecurityUtils.getUserContent().getEntId());
        query.eq(EntPersonnel::getPersonnelId, personnelId);
        return entPersonnelMapper.delete(lq);
    }

    @Override
    public void changeSort(String id, int index) {
        Personnel obj = getById(id);
        obj.setSort(index);
        getBaseMapper().updateById(obj);
    }

    @Override
    public Personnel queryById(String id) {
        return getBaseMapper().selectById(id);
    }

    @Override
    public Personnel queryById(String id, String tenantId) {
        Ent ent = entService.queryByTenantId(tenantId);
        if (ent == null) {
            throw new BusinessException("指定的租户无效。");
        }
        LambdaQueryWrapper<EntPersonnel> lq = Wrappers.lambdaQuery();
        lq.eq(EntPersonnel::getEntId, ent.getId());
        lq.eq(EntPersonnel::getPersonnelId, id);
        lq.eq(EntPersonnel::getIsDelete, false);
        int cnt = entPersonnelMapper.selectCount(lq);
        if (cnt > 0) {
            return queryById(id);
        } else {
            return null;
        }
    }

    @Override
    public Personnel queryByUserId(String userId) {
        LambdaQueryWrapper<Personnel> lq = Wrappers.lambdaQuery();
        lq.eq(Personnel::getUserId, userId);
        return baseMapper.selectOne(lq);
    }

    @Override
    public List<String> queryUserIdByPersonnel(List<String> personnelIds) {
        LambdaQueryWrapper<PersonnelExt> lq = Wrappers.lambdaQuery();
        lq.in(PersonnelExt::getPersonnelId, personnelIds);
        return personnelExtMapper.selectList(lq).stream().map(s -> s.getUserId()).distinct().collect(Collectors.toList());
    }

    @Override
    public Personnel queryByPhone(String phone) {
        LambdaQueryWrapper<Personnel> lq = Wrappers.lambdaQuery();
        lq.eq(Personnel::getTel, phone);
        return baseMapper.selectOne(lq);
    }

    @Override
    public IPage<PersonnelExt> query(String searchText, String deptId, int pageIndex, int pageSize) {
        Page<PersonnelExt> page = new Page(pageIndex, pageSize);
        LambdaQueryWrapper<PersonnelExt> lq = Wrappers.lambdaQuery();
        if (!StringUtils.isNullOrEmpty(deptId)) {
            lq.eq(PersonnelExt::getDeptId, deptId);
        }
        lq.eq(PersonnelExt::getEntId, SecurityUtils.getUserContent().getEntId());
        lq.eq(PersonnelExt::getIsDelete, false);
        if (!StringUtils.isNullOrEmpty(searchText)) {
            lq.and(obj -> obj.like(PersonnelExt::getName, searchText).or()
                    .like(PersonnelExt::getTel, searchText).or());
        }
        lq.orderByAsc(PersonnelExt::getSort);
        return personnelExtMapper.selectPage(page, lq);
    }

    @Override
    public IPage<PersonnelExt> queryByRoleCode(String roleCode, int pageSize, int pageIndex) {
        Page<PersonnelExt> page = new Page(pageIndex, pageSize);

        LambdaQueryWrapper<AppUserRoleExt> roleQuery = Wrappers.lambdaQuery();
        roleQuery.eq(AppUserRoleExt::getCode, roleCode);
        List<String> ids = appUserRoleExtMapper.selectList(roleQuery).stream().map(s -> s.getUserId()).collect(Collectors.toList());
        if (StringUtils.isNullOrEmpty(ids)) {
            return page;
        }

        LambdaQueryWrapper<PersonnelExt> lq = Wrappers.lambdaQuery();
        lq.in(PersonnelExt::getUserId, ids);
        return personnelExtMapper.selectPage(page, lq);
    }
}